/**
 * 
 */
package com.fnic.pearl.scheduler.action;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import com.fnic.pearl.scheduler.constant.CondHeaderField;
import com.fnic.pearl.scheduler.constant.ModuleType;
import com.fnic.pearl.scheduler.constant.PearlErrorCode;
import com.fnic.pearl.scheduler.dao.SchedulerStore;
import com.fnic.pearl.scheduler.model.HeartBeatResp;
import com.fnic.pearl.scheduler.model.VersionUpdate;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

/**
 * 版本升级接口
 * 
 * @author HuHaiyang
 * @date 2014年2月14日
 */
public class VersionUpdateServlet extends HttpServlet
{
    private static final long serialVersionUID = 1L;
    private static final Logger LOG = Logger.getLogger(VersionUpdateServlet.class);
    private Gson gson = new GsonBuilder()
                .disableHtmlEscaping()
                .excludeFieldsWithoutExposeAnnotation().create();

    /**
     * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
    {
        List<VersionUpdate> lstVersionUpdate = null;
        try
        {
        	BufferedReader is =  new BufferedReader( new InputStreamReader(req.getInputStream()));
        	StringBuffer testStr = new StringBuffer();
        	String line = "";
        	while ((line = is.readLine()) != null) {
        		testStr.append(line);
			}
        	System.out.println(testStr);
            lstVersionUpdate = gson.fromJson(testStr.toString(), 
                    new TypeToken<List<VersionUpdate>>(){}.getType());
        }
        catch (Exception e)
        {
            LOG.warn("version update parse exception - " + e.getMessage());
            resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            return ;
        }
        
        if (lstVersionUpdate == null)
        {
            LOG.warn("version update is null!");
            resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            return ;
        }
        else if (lstVersionUpdate.size() == 0)
        {
            LOG.warn("version update is empty!");
            resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            return ;
        }
        
        List<UpdateError> errors = new ArrayList<UpdateError>();
        for (VersionUpdate vu : lstVersionUpdate)
        {
            if (vu == null)
            {
                LOG.warn("invalid versionUpdate, is null!");
                continue;
            }
            else if (vu.getUpdateId() <= 0)
            {
                LOG.warn("invalid versionUpdate, updateId [" + vu.getUpdateId() + "] <= 0");
                errors.add(new UpdateError(vu.getUpdateId(), PearlErrorCode.SCHD_ERR_SVC_UPD_ID_INVALID));
                continue;
            }
            else if (vu.getModuleId() <= 0)
            {
                LOG.warn("invalid versionUpdate [" + vu.getUpdateId() 
                        + "], moduleId [" + vu.getModuleId() + "] <= 0");
                errors.add(new UpdateError(vu.getUpdateId(), PearlErrorCode.SCHD_ERR_SVC_MOD_ID_INVALID));
                continue;
            }
            else if (vu.getUpdateVersion() == null || vu.getUpdateVersion().length() == 0)
            {
                LOG.warn("invalid versionUpdate [" + vu.getUpdateId() + "] updateVersion");
                errors.add(new UpdateError(vu.getUpdateId(), PearlErrorCode.SCHD_ERR_SVC_UPD_VER_INVALID));
                continue;
            }
            
            LOG.info("recv version update - " + vu);
            
            switch (vu.getModuleType())
            {
            case ModuleType.PROBE_X86:
            case ModuleType.PROBE_MIPS:
                HeartBeatResp hbr = new HeartBeatResp(
                        CondHeaderField.HB_BTYPE_VER_UPD, gson.toJson(vu));
                SchedulerStore.getInstance().pushHbResp(vu.getModuleId(), hbr);
                break;
                
            case ModuleType.SCHEDULER:
                // TODO 针对调度器自身的升级
                break;
                
            default:
                LOG.warn("unsupport module type - " + lstVersionUpdate);
                errors.add(new UpdateError(vu.getUpdateId(), PearlErrorCode.SCHD_ERR_SVC_MOD_TYPE_INVALID));
                continue;
            }
        }
        
        if (errors.size() == 0)
        {
            resp.setStatus(HttpServletResponse.SC_OK);
            return ;
        }
        
        resp.setContentType("application/json;charset=utf-8");
        resp.setStatus(HttpServletResponse.SC_FORBIDDEN);
        resp.getWriter().write(gson.toJson(errors));
        resp.getWriter().flush();
    }
    
    /**
     * 升级任务错误信息
     */
    public class UpdateError
    {
        private int updateId;
        private int errorCode;
        
        public UpdateError(int updateId, int errorCode)
        {
            super();
            this.updateId = updateId;
            this.errorCode = errorCode;
        }
        
        /**
         * @return the updateId
         */
        public int getUpdateId()
        {
            return updateId;
        }
        /**
         * @param updateId the updateId to set
         */
        public void setUpdateId(int updateId)
        {
            this.updateId = updateId;
        }
        /**
         * @return the errorCode
         */
        public int getErrorCode()
        {
            return errorCode;
        }
        /**
         * @param errorCode the errorCode to set
         */
        public void setErrorCode(int errorCode)
        {
            this.errorCode = errorCode;
        }
        /**
         * @see java.lang.Object#toString()
         */
        @Override
        public String toString()
        {
            StringBuilder builder = new StringBuilder();
            builder.append("UpdateError [updateId=").append(updateId)
                    .append(", errorCode=").append(errorCode).append("]");
            return builder.toString();
        }
    }
}
